package org.apache.zookeeper;

import org.apache.zookeeper.AsyncCallback.GetDataCallback;
import org.apache.zookeeper.AsyncCallback.SetDataCallback;
import org.apache.zookeeper.server.paxos2.Configuration;

import java.util.Random;

/**
 * Created by IntelliJ IDEA. User: iodine Date: May 22, 2011 Time: 9:33:01 PM To
 * change this template use File | Settings | File Templates.
 */
public class Test {
	private static BlockStorage s;

	private static int totalOps = 1000000;

	private static long lastTime = System.currentTimeMillis();
	private static int finishedOps = 0;

	private static final Object lock = new Object();

	private static class ReadCallback implements GetDataCallback {
		public void processResult(int rc, long blockId, Object ctx, byte data[]) {
			System.out.println("read " + blockId + " size=" + data.length);
			synchronized (lock) {
				finishedOps++;
				if (finishedOps % 10000 == 0) {
					System.out.println("throughput = " + 10000 * 1000
							/ (System.currentTimeMillis() - lastTime));
					lastTime = System.currentTimeMillis();
				}
				if (totalOps == finishedOps) {
					lock.notify();
				}
			}
		}
	}

	private static class WriteCallback implements SetDataCallback {
		public void processResult(int rc, long blockId, Object ctx) {
			// System.out.println("write " + blockId);
			synchronized (lock) {
				finishedOps++;
				if (finishedOps % 10000 == 0) {
					System.out.println("throughput = " + 10000 * 1000
							/ (System.currentTimeMillis() - lastTime));
					lastTime = System.currentTimeMillis();
				}

				if (totalOps == finishedOps) {
					lock.notify();
				}
			}
		}
	}

	public static void testWrite() throws Exception {
		int total = (int) (Configuration.totalSize / Configuration.blockSize) - 1;
		WriteCallback cb = new WriteCallback();
		Random r = new Random();
		byte[] data = new byte[Configuration.blockSize];
		long start = System.currentTimeMillis();
		int blockId;
		for (long i = 0; i < totalOps; i++) {
			if (sequential)
				blockId = (int) i;
			else
				blockId = r.nextInt(total);
			s.write(blockId, data, cb, null);
		}
		synchronized (lock) {
			while (finishedOps != totalOps)
				lock.wait();
		}

		System.out.println("time = " + (System.currentTimeMillis() - start));
		// System.exit(0);
		// Thread.sleep(500000);
	}

	public static void testRead() throws Exception {
		int total = (int) (Configuration.totalSize / Configuration.blockSize) - 1;
		WriteCallback tmp = new WriteCallback();
		s.write(0, new byte[Configuration.blockSize], tmp, null);
		Thread.sleep(5000);
		ReadCallback cb = new ReadCallback();
		Random r = new Random();
		long start = System.currentTimeMillis();
		int blockId;
		for (int i = 0; i < totalOps; i++) {
			if (sequential)
				blockId = i;
			else
				blockId = r.nextInt(total);
			s.read(blockId, cb, null);
		}
		synchronized (lock) {
			while (finishedOps != totalOps)
				lock.wait();
		}
		System.out.println("time = " + (System.currentTimeMillis() - start));

	}

	private static boolean read;
	private static boolean sequential;

	public static void main(String[] args) throws Exception {
		if (args.length != 3) {
			System.err
					.println("java Test <id> <read/write> <sequential/random>");
			return;
		}

		read = (Integer.parseInt(args[1]) == 1);
		sequential = (Integer.parseInt(args[2]) == 1);

		s = new BlockStorage("application1,application2,application3", Integer
				.parseInt(args[0]));
		// if(Integer.parseInt(args[0])==1)
		if (read)
			testRead();
		else
			testWrite();
		System.exit(0);
	}
}
